package com.franklin.ideaplugin.easytesting.spring.config;

import com.franklin.ideaplugin.easytesting.common.utils.PortUtils;
import com.franklin.ideaplugin.easytesting.controllerclient.support.ControllerClientAutoConfiguration;
import com.franklin.ideaplugin.easytesting.core.rpc.NettyServer;
import com.franklin.ideaplugin.easytesting.spring.dubbo.EasyTestingDubboAutoConfiguration;
import com.franklin.ideaplugin.easytesting.spring.invoke.SpringMethodInvoker;
import com.franklin.ideaplugin.easytesting.spring.invoke.SpringScriptObjectPropertyFiller;
import com.franklin.ideaplugin.easytesting.spring.lifecycle.EasyTestingLifeCycle;
import com.franklin.ideaplugin.easytesting.spring.registry.SpringFileRegistry;
import com.franklin.ideaplugin.easytesting.spring.registry.SpringPortHolder;
import com.franklin.ideaplugin.easytesting.spring.utils.SpringUtil;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.io.IOException;
import java.util.Objects;

/**
 * @author Ye Junhui
 * @since 2023/5/15
 */
@Configuration
@ConditionalOnProperty(name = "easy-testing.enable",matchIfMissing = true)
@Import({
        MyServerProperties.class,
        ControllerClientAutoConfiguration.class,
        EasyTestingDubboAutoConfiguration.class
})
public class EasyTestingAutoConfiguration {

    @Bean
    public EasyTestingProperties easyTestingProperties(){
        return new EasyTestingProperties();
    }

    @Bean
    public SpringScriptObjectPropertyFiller easyTestingSpringScriptObjectPropertyFiller(){
        return new SpringScriptObjectPropertyFiller();
    }

    @Bean
    @Autowired
    public EasyTestingLifeCycle easyTestingLifeCycle(
            SpringMethodInvoker springMethodInvoker,
            NettyServer nettyServer,
            EasyTestingProperties easyTestingProperties,
            SpringFileRegistry springFileRegistry,
            SpringScriptObjectPropertyFiller springScriptObjectPropertyFiller
    ){
        return new EasyTestingLifeCycle(
                springMethodInvoker,
                nettyServer,
                easyTestingProperties,
                springFileRegistry,
                springScriptObjectPropertyFiller
        );
    }

    @Bean
    @Autowired
    public SpringPortHolder easyTestingSpringPortHolder(
            ServerProperties serverProperties
    ){
        //注册端口号
        try {
            Integer serverPort = serverProperties.getPort();
            if (Objects.isNull(serverPort)){
                serverPort = 8080;
            }
            int port = ((serverPort + 20202) * serverProperties.hashCode()) % 65535 + 1;
            port = Math.abs(port);
            int usablePort = PortUtils.getUsablePort(port);
            return new SpringPortHolder(usablePort);
        } catch (IOException e) {
            return new SpringPortHolder(-1);
        }
    }

    @Bean
    @Autowired
    public SpringFileRegistry easyTestingSpringFileRegistry(
            SpringPortHolder springPortHolder,
            EasyTestingProperties easyTestingProperties
    ){
        return new SpringFileRegistry(springPortHolder.getPort(),easyTestingProperties);
    }

    @Bean
    public SpringUtil easyTestingSpringUtil(){
        return new SpringUtil();
    }

    @Bean
    @Autowired
    public SpringMethodInvoker easyTestingSpringMethodInvoker(
            OkHttpClient okHttpClient,
            MyServerProperties myServerProperties
    ){
        return new SpringMethodInvoker(okHttpClient,myServerProperties);
    }

    @Bean("easyTestingNettyServer")
    @Autowired
    public NettyServer easyTestingNettyServer(
            SpringPortHolder springPortHolder
    ){
        if (springPortHolder.getPort() < 0){
            return new NettyServer(-1);
        }
        //启动netty服务器
        NettyServer nettyServer = new NettyServer(springPortHolder.getPort());
        return nettyServer;
    }

}
